package com.example.nacosdemo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.nacosdemo.client.OrderClient;
import com.example.nacosdemo.dto.ChangeOrderDTO;
import com.example.nacosdemo.dto.ReduceDTO;
import com.example.nacosdemo.entity.Product;
import com.example.nacosdemo.exception.ServiceException;
import com.example.nacosdemo.mapper.ProductMapper;
import com.example.nacosdemo.service.ProductService;
import com.example.nacosdemo.utils.redis.RedisDistLock;
import com.example.nacosdemo.utils.redis.RedisDistLockWithDog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
@AllArgsConstructor
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    private final ProductMapper productMapper;

    private final RedisDistLock redisDistLock;

    private final RedisDistLockWithDog redisDistLockWithDog;

    private final RedissonClient redissonClient;

    private final OrderClient orderClient;

    @Override
    public Boolean reduce(ReduceDTO dto) {
        Boolean flag = false;
        try {
            redisDistLock.setLockName(dto.getProductCode());
            redisDistLock.lock();
            Boolean stockFlag = hasStock(dto);
            if (stockFlag) {
                productMapper.reduce(dto.getProductCode());
                flag = true;
            } else {
                throw new ServiceException("库存不够了");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            redisDistLock.unlock();
        }
        return flag;
    }

    @Override
    public void reduceWithDog(ReduceDTO dto) {
        try {
            redisDistLockWithDog.setLockName(dto.getProductCode());
            redisDistLockWithDog.lock();
            Thread.sleep(20000);
            Boolean stockFlag = hasStock(dto);
            if (stockFlag) {
                productMapper.reduce(dto.getProductCode());
            } else {
                throw new ServiceException("库存不够了");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            redisDistLockWithDog.unlock();
        }
    }

    @Override
    public void reduceWithRedisson(ReduceDTO dto) {
        RLock lock = redissonClient.getLock(dto.getProductCode());
        try {
            lock.lock(1, TimeUnit.SECONDS);
            Thread.sleep(20000);
            Boolean stockFlag = hasStock(dto);
            if (stockFlag) {
                productMapper.reduce(dto.getProductCode());
            } else {
                throw new ServiceException("库存不够了");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlockAsync();
        }
    }

    @Override
    public void reduceAndChangeOrder(ReduceDTO dto) {
        Boolean reduce = reduce(dto);
        if (reduce){
            ChangeOrderDTO orderDTO = new ChangeOrderDTO();
            orderDTO.setOrderNum(dto.getOrderNum());
            orderDTO.setFlag(reduce);
            orderClient.changeOrder(orderDTO);
        }
    }

    private Boolean hasStock(ReduceDTO dto) {
        LambdaQueryWrapper<Product> wrapper = Wrappers
                .<Product>lambdaQuery()
                .eq(Product::getProductCode, dto.getProductCode());
        Product one = this.getOne(wrapper);
        if (one.getStock() > 0){
            return true;
        }else {
            return false;
        }
    }


}
